#ifndef K_NET_SCENE_H
#define K_NET_SCENE_H
#pragma once

#include "KMultiplexor.h"
#include <vector>

class KNetScene;
class KSocketAction;

class KNetItem : KNoCopy {
protected:
    enum EventFilterFlag {
        FilterNone          = 0x000,
        FilterAccepted      = 0x001,
        FilterClosing       = 0x002,
        FilterConnected     = 0x004,
        FilterCreated       = 0x008,
        FilterError         = 0x010,
        FilterMessage       = 0x020,
        FilterReceived      = 0x040,
        FilterSent          = 0x080,
        FilterTransmitted   = 0x100,
        FilterAll           = 0xfff
    };
protected:
    KNetItem() : m_scene(NULL) {}
    virtual ~KNetItem() = 0;
protected:
    virtual int filter() const  { return KNetItem::FilterNone; }
    KNetScene *scene() const    { return m_scene; }
protected:
    // TCP
    KSocket *addAcceptor(const KIAddress &addrLocal,
        KSocketAction *action = NULL, int sendBufSize = -1, bool reuseAddrLocal = false, size_t extra = 0);
    KSocket *addConnector(const KIAddress &addrLocal, const KIAddress &addrRemote,
        KSocketAction *action = NULL, int sendBufSize = -1, bool reuseAddrLocal = false);
    // UDP
    KSocket *addMessenger(const KIAddress &addrLocal,
        KSocketAction *action = NULL, int sendBufSize = -1, bool reuseAddrLocal = false);
protected:
    static KSocketAction *getAction(KSocket *sock);
    bool setAction(KSocket *sock, KSocketAction *action = NULL, bool take = false);
protected:
    // For both TCP and UDP
    bool postMessage(KSocket *sock, KKey *key = NULL);
    bool receive(KSocket *sock, size_t length = 0, KKey *key = NULL);
    // For TCP only
    bool send(KSocket *sock, KStorage *storage, size_t length = 0);
    bool send(KSocket *sock, const void *data, size_t length, KKey *key = NULL);
    bool transmit(KSocket *sock, HANDLE hFile, size_t length = 0, KKey *key = NULL, size_t blockLen = 0, KPackage *head = NULL, KPackage *tail = NULL);
    // For UDP only
    bool sendTo(KSocket *sock, const KIAddress &addrRemote, const void *data, size_t length, KKey *key = NULL);
protected:
    // For lifetime control
    void ensureAlive(KSocket *sock, bool always = true);
    KDef::Life lifeBegin(KSocket *sock);
    void lifeEnd(KSocket *sock, KDef::Life life);
protected:
    virtual void onStarted() {}
    virtual void onStopped() {}
    virtual void onStopping() {}
protected:
    // For TCP server only
    virtual void onAccepted(KSocket *sock, KKey *key);
    virtual void onFatalError(KSocket *sock, KDef::SockError type, DWORD error);
    // For TCP only
    virtual void onConnected(KSocket *sock);
    virtual void onTransmitted(KSocket *sock, KKey *&key, HANDLE file, size_t length);
    // For UDP only
    virtual void onCreated(KSocket *sock);
    // For both TCP and UDP
    virtual void onClosing(KSocket *sock, bool stopped);
    virtual void onError(KSocket *sock, KDef::SockError type, DWORD error);
    virtual void onMessage(KSocket *sock, KKey *&key);
    virtual void onReceived(KSocket *sock, KKey *&key, void *data, size_t length, bool more);
    virtual void onSent(KSocket *sock, KKey *&key, void *data, size_t length);
private:
    KNetScene *m_scene;
    friend class KNetScene;
    friend class KSocketAction;
};

class KNetScene : protected KMultiplexor, protected KLockable {
public:
    explicit KNetScene(
        size_t numOfWorkers,
        size_t maxPoolSize = KDef::DefaultPoolSize,
        size_t chunkSize = KDef::DefaultChunkSize);
    virtual ~KNetScene();
public:
    using KMultiplexor::isRunning;
    using KMultiplexor::start;
public:
    using KMultiplexor::chunkSize;
    using KMultiplexor::maxPoolSize;
    using KMultiplexor::poolSize;
public:
    void install(KNetItem *item);
    bool stopAll();
protected:
    virtual void onAccepted(KSocket *sock, KKey *key);
    virtual void onClosing(KSocket *sock, bool stopped);
    virtual void onConnected(KSocket *sock);
    virtual void onCreated(KSocket *sock);
    virtual void onError(KSocket *sock, KDef::SockError type, DWORD error);
    virtual void onMessage(KSocket *sock, KKey *&key);
    virtual void onReceived(KSocket *sock, KKey *&key, void *&data, size_t length, bool more);
    virtual void onSent(KSocket *sock, KKey *&key, void *&data, size_t length);
    virtual void onStopping();
    virtual void onTransmitted(KSocket *sock, KKey *&key, HANDLE file, size_t length);
    virtual bool startImp();
    virtual bool stopImp(DWORD ms);
private:
    std::vector<KNetItem *> m_items;
    friend class KNetItem;
};

#endif // K_NET_SCENE_H